package com.ipan.builder.ext.entity;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.ipan.builder.entity.EntityDefineNaming;
import com.ipan.builder.entity.annotation.Build;
import com.ipan.builder.entity.annotation.TableComment;
import com.ipan.builder.ext.entity.annotation.DefColumn;
import com.ipan.builder.ext.entity.annotation.DefTable;
import com.ipan.builder.ext.entity.annotation.DefTransient;

/**
 * 自定义实体类配置信息
 * <pre>
 * 主要为JDBC、Mybatis开发时候使用。
 * 
 * 实体名称还可以通过以下变量来访问：
 * ${name1} = AaaBbb
 * ${name2} = aaaBbb
 * ${name3} = aaa_bbb
 * ${name4} = aaa-bbb
 * ${name5} = aaabbb
 * ${name6} = AAABBB
 * 
 * 自定义接口的名称默认使用${name1}的名称；
 * </pre>
 * @author iPan
 * @version 2015-01-24
 */
public class DefEntityCfg implements EntityDefineNaming {

	/** 名称格式：AaaBbb */
	private Class<?> entityClass;
	
	/** 实体名称 */
	private String entityName;

	/** @Table name */
	private String tableName = "";
	
//	/** @Table catalog */
//	private String tableCatalog = "";
//	/** @Table schema */
//	private String tableSchema = "";
	
	/** @TableComment */
	private String tableComment = "";
	
	/** 字段容器（实体字段名->字段配置） */
	private Map<String, DefColumnCfg> columnContext = new HashMap<String, DefColumnCfg>();
	/** 字段容器（数据库字段名->字段配置） */
	private Map<String, DefColumnCfg> columnContext2 = new HashMap<String, DefColumnCfg>();
	
	/** 自定义命名策略，默认返回name1格式； */
	private EntityDefineNaming naming = new EntityDefineNaming() {

		public String getDefName1() {
			return getName1();
		}

		public String getDefName2() {
			return getName1();
		}

		public String getDefName3() {
			return getName1();
		}

		public String getDefName4() {
			return getName1();
		}

		public String getDefName5() {
			return getName1();
		}
		
	};

	public DefEntityCfg(Class<?> entityClass) {
		this.entityClass = entityClass;
		this.entityName = entityClass.getSimpleName();
		
		// 解析@Table注释
		DefTable table = entityClass.getAnnotation(DefTable.class);
		if (table != null) {
			// 表名设置为小写
			if (StringUtils.isEmpty(table.name())) { // 默认使用类名以“_”分隔
				this.tableName = toSplitName(this.entityName, "_", true);
			} else {
				this.tableName = table.name();
			}
//			this.tableSchema = table.schema();
//			this.tableCatalog = table.catalog();
		} else {
			this.tableName = toSplitName(this.entityName, "_", true);
		}
		// 解析@TableComment注释
		TableComment tableComment = entityClass.getAnnotation(TableComment.class);
		if (tableComment != null) {
			this.tableComment = tableComment.value();
		}
		// 解析所有字段
		List<Field> fieldList = getAllFields(entityClass);
		for (Field field : fieldList) {
			if (Modifier.isStatic(field.getModifiers())) {
				continue;
			}
			DefColumnCfg columnCfg = new DefColumnCfg(this, field.getName(), field.getType());
			// 解析@Column
			DefColumn columnAnn = field.getAnnotation(DefColumn.class);
			if (columnAnn != null) {
				// 字段名字设为小写
				if (StringUtils.isEmpty(columnAnn.name())) { // @DefColumn name
					columnCfg.setName(toSplitName(field.getName(), "_", true));
				} else {
					columnCfg.setName(columnAnn.name());
				}
			    columnCfg.setLength(columnAnn.length()); // @DefColumn length
			    columnCfg.setNullable(columnAnn.nullable()); // @Column nullable
			} else {
				columnCfg.setName(toSplitName(field.getName(), "_", true));
			}
			
			// 解析@Build
			Build buildAnn = field.getAnnotation(Build.class);
			if (buildAnn != null) {
				columnCfg.setSearchColumn(buildAnn.searchColumn()); // 查询字段
				columnCfg.setListColumn(buildAnn.listColumn());	// 列表字段
				columnCfg.setSubmitColumn(buildAnn.submitColumn());	// 表单提交字段
				columnCfg.setHiddenColumn(buildAnn.hiddenColumn());	// 表单隐藏字段
				columnCfg.setComment(buildAnn.comment()); // 数据库字段注释
			}
			
			// 解析@Transient
			DefTransient transientAnn = field.getAnnotation(DefTransient.class);
			if (transientAnn != null) {
				columnCfg.setTransient(true);
			}
			columnContext.put(columnCfg.getColumnName(), columnCfg);
			columnContext2.put(columnCfg.getName(), columnCfg);
		}
	}
	
	public List<DefColumnCfg> getAllColumnCfg() {
		return new ArrayList<DefColumnCfg>(columnContext.values());
	}
	
	/**
	 * 获取Insert设置的SET字段
	 */
	public String getInsertSets() {
		List<DefColumnCfg> list = getAllColumnCfg();
		StringBuilder buf = new StringBuilder();
		int i = 0;
		for (DefColumnCfg col : list) {
			if (col.isTransient()) {
				continue;
			}
			if (i > 0) {
				buf.append(", ");
			}
			buf.append(col.getName());
			i++;
		}
		return buf.toString();
	}
	
	/**
	 * 获取Insert设置的VALUES字段
	 */
	public String getInsertValues() {
		return getInsertValues("#{?}");
	}
	
	/**
	 * 获取Insert设置的VALUES字段
	 */
	public String getInsertValues(String pattern) {
		List<DefColumnCfg> list = getAllColumnCfg();
		StringBuilder buf = new StringBuilder();
		int i = 0;
		for (DefColumnCfg col : list) {
			if (col.isTransient()) {
				continue;
			}
			if (i > 0) {
				buf.append(", ");
			}
			String val = pattern.replaceAll("\\?", col.getColumnName());
			buf.append(val);
			i++;
		}
		return buf.toString();
	}
	
	/**
	 * 获取Update设置的字段
	 */
	public String getUpdateSets() {
		return getUpdateSets("#{?}");
	}
	
	/**
	 * 获取Update设置的字段
	 */
	public String getUpdateSets(String pattern) {
		List<DefColumnCfg> list = getAllColumnCfg();
		StringBuilder buf = new StringBuilder();
		for (int i=0, len=list.size(); i<len; ++i) {
			if (!list.get(i).isSubmitColumn()) {
				continue;
			}
			if (buf.length() > 0) {
				buf.append(", ");
			}
			String val = list.get(i).getName() + " = " + pattern.replaceAll("\\?", list.get(i).getColumnName());
			buf.append(val);
		}
		return buf.toString();
	}
	
	/**
	 * 根据实体字段名获取
	 */
	public DefColumnCfg getColumnCfg(String columnName) {
		return columnContext.get(columnName);
	}
	
	/**
	 * 根据数据库字段名获取（小写）
	 */
	public DefColumnCfg getColumnCfgByName(String name) {
		return columnContext2.get(name);
	}
	
	public Class<?> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<?> entityClass) {
		this.entityClass = entityClass;
	}

	public String getEntityName() {
		return entityName;
	}

	public void setEntityName(String entityName) {
		this.entityName = entityName;
	}

	/**
	 * 名称格式：AaaBbb
	 */
	public String getName1() {
		return this.entityName;
	}

	/**
	 * 名称格式：aaaBbb
	 */
	public String getName2() {
		return StringUtils.uncapitalize(this.entityName);
	}

	/**
	 * 名称格式：aaa_bbb
	 */
	public String getName3() {
		return toSplitName(this.entityName, "_", true);
	}
	
	/**
	 * 名称格式：aaa-bbb
	 */
	public String getName4() {
		return toSplitName(this.entityName, "-", true);
	}

	/**
	 * 名称格式：aaabbb
	 */
	public String getName5() {
		return this.entityName.toLowerCase();
	}

	/**
	 * 名称格式：AAABBB
	 */
	public String getName6() {
		return this.entityName.toUpperCase();
	}

	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public EntityDefineNaming getNaming() {
		return naming;
	}

	public void setNaming(EntityDefineNaming naming) {
		this.naming = naming;
	}

	public String getDefName1() {
		return this.naming.getDefName1();
	}

	public String getDefName2() {
		return this.naming.getDefName2();
	}

	public String getDefName3() {
		return this.naming.getDefName3();
	}

	public String getDefName4() {
		return this.naming.getDefName4();
	}

	public String getDefName5() {
		return this.naming.getDefName5();
	}

	public String getTableComment() {
		return tableComment;
	}

	public void setTableComment(String tableComment) {
		this.tableComment = tableComment;
	}
	
	private List<Field> getAllFields(Class<?> entityClass) {
		List<Field> fieldList = new ArrayList<Field>();
		for (Class<?> supperClass = entityClass; supperClass != Object.class; supperClass = supperClass.getSuperclass()) {
			Field[] fields = supperClass.getDeclaredFields();
			for (Field f : fields) {
				fieldList.add(f);
			}
		}
		Collections.reverse(fieldList);
		return fieldList;
	}
	
	private static String toSplitName(String name, String separator, boolean isLowerCase) {
		if (name == null || name.length() <= 1) {
			return name;
		}
		
		StringBuilder buf = new StringBuilder();
		buf.append(name.charAt(0));
		for (int i=1, len=name.length(); i<len; ++i) {
			char chr = name.charAt(i);
			if (Character.isUpperCase(chr)) {
				buf.append(separator);
			}
			buf.append(chr);
		}
		return (isLowerCase) ? buf.toString().toLowerCase() : buf.toString().toUpperCase();
	}
}
